// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: jaewon

#include "coin1/base/datetime_util.h"

#include <algorithm>
#include <cmath>
#include <cstring>
#include <ctime>

#include <glog/logging.h>

std::optional<int64_t> ParseISO8601String(const std::string& dt_str) {
  if (dt_str.size() < 19 || dt_str.size() > 29) return std::nullopt;

  std::string_view dt_part(dt_str.data(), 19);
  std::string_view frac_part;
  if (dt_str.size() == 20) {
    return std::nullopt;
  } else if (dt_str.size() > 20) {
    if (dt_str[19] != '.') return std::nullopt;
    frac_part = std::string_view(dt_str.data() + 20, std::min(dt_str.size() - 20, 9UL));
  }

  struct tm parts;
  memset(&parts, 0, sizeof(parts));
  {
    auto res = strptime(dt_part.data(), "%Y-%m-%dT%H:%M:%S", &parts);
    if (res == nullptr) return std::nullopt;
  }

  time_t posix_t = mktime(&parts);
  if (posix_t == -1) {
    return std::nullopt;
  }

  int64_t ts = posix_t * 1000000000LL;

  int64_t frac_multiplier = 1;
  int64_t frac = 0;
  if (!frac_part.empty()) {
    frac = atoll(frac_part.data());
    if (frac_part.size() < 9) {
      frac_multiplier = pow(10, 9 - frac_part.size());
    }
    ts += frac * frac_multiplier;
  }
  return ts;
}
